package com.bupt.service.common.impl;

import com.bupt.basic.BasicNetWork;
import com.bupt.entity.Route;
import com.bupt.exception.BaseException;
import lombok.Data;

import java.io.Serializable;
import java.util.*;

public class TbKangHuiServiceUtil {
    /**
     * 判断路由中链路承载的物理底层是否含有相应的fiber链路
     * 若含有，则被影响，返回true
     */
    public static boolean judgeAffected(String fiberLinkId, String layer, List<String> routeLinkIds,
                                        BasicNetWork basicNetWork) {
        if (routeLinkIds == null || routeLinkIds.size() == 0) {
            return true;
        }
        switch (layer) {
            case "WDM":
                for (String s : routeLinkIds) {
                    for (BasicNetWork.BasicLink w : basicNetWork.getWdmLinks()) {
                        if (w.getId().equals(s)) {
                            for (String s1 : w.getFiberLinkIdSet()) {
                                if (s1.equals(fiberLinkId)) {
                                    return true;
                                }
                            }
                        }
                    }
                }
                break;
            case "OTN":
                for (String s : routeLinkIds) {
                    for (BasicNetWork.BasicLink o : basicNetWork.getOtnLinks()) {
                        if (o.getId().equals(s)) {
                            for (String s1 : o.getFiberLinkIdSet()) {
                                if (s1.equals(fiberLinkId)) {
                                    return true;
                                }
                            }
                        }
                    }
                }
                break;
            case "SDH":
                for (String s : routeLinkIds) {
                    for (BasicNetWork.BasicLink sdh : basicNetWork.getSdhLinks()) {
                        if (sdh.getId().equals(s)) {
                            for (String s1 : sdh.getLoadOnLinksIds()) {
                                if (s1.equals(fiberLinkId)) {
                                    return true;
                                }
                            }
                        }
                    }
                }
                break;
        }
        return false;
    }

    //判断此BasicLink底层fiber链路组是否与allBreakLinks有交集
    public static boolean isBreak(BasicNetWork.BasicLink basicLink, Set<String> allBreakLinks) {
        if (allBreakLinks == null || allBreakLinks.isEmpty()) {
            return false;
        }
        for (String fiberId : basicLink.getFiberLinkIdSet()) {
            for (String breakId : allBreakLinks) {
                if (fiberId.equals(breakId)) {
                    return true;
                }
            }
        }
        return false;
    }

    /**
     *
     * @param serviceLayer 业务所属层
     * @param allBreakFiberLinks 所有断开的fiberId
     * @param serviceRate 业务带宽
     * @param basicNetWork 项目网络
     * @return
     * @throws BaseException
     */
    //在相应层级中，排除底层含breakFiberLink的链路，返回剩余链路
    public static Set<BasicNetWork.BasicLink> removeRelatedLinks(String serviceLayer, Set<String> allBreakFiberLinks, double serviceRate
            ,BasicNetWork basicNetWork) throws BaseException {
        Set<BasicNetWork.BasicLink> res = new HashSet<>();
        List<BasicNetWork.BasicLink> layerLinks = null;
        switch (serviceLayer) {
            case "WDM":
                layerLinks = basicNetWork.getWdmLinks();
                break;
            case "OTN":
                layerLinks = basicNetWork.getOtnLinks();
                break;
            case "SDH":
                layerLinks = basicNetWork.getSdhLinks();
                break;
            default:
                throw new BaseException("此业务的所属层名字不规范");
        }
        if (layerLinks == null) {
            throw new BaseException("此项目无"+serviceLayer+"层链路");
        }
        for (BasicNetWork.BasicLink basicLink : layerLinks) {
            if (!isBreak(basicLink, allBreakFiberLinks)) {
                res.add(basicLink);
            }
        }
        if (basicNetWork.getSatelliteLinks() != null) {
            for (BasicNetWork.BasicLink sate : basicNetWork.getSatelliteLinks()) {
                if (sate.getRate() > serviceRate) {
                    res.add(sate);
                }
            }
        }
        if (basicNetWork.getShortWaveLinks() != null) {
            for (BasicNetWork.BasicLink shortWave : basicNetWork.getShortWaveLinks()) {
                if (shortWave.getRate() > serviceRate) {
                    res.add(shortWave);
                }
            }
        }
        return res;
    }

    public static Route generateRoute(List<BasicNetWork.BasicLink> routeList, BasicNetWork.BasicNode origin, BasicNetWork.BasicNode destination) throws BaseException {
        Route route = new Route();

        Set<String> nodeList = new LinkedHashSet<>();
        List<String> nodeNameList = new ArrayList<>();
        List<String> linkList = new ArrayList<>();
        List<String> linkNameList = new ArrayList<>();
        List<String> linkTypeList = new ArrayList<>();
        for (BasicNetWork.BasicLink link : routeList) {
            nodeList.add(link.getNodeHead());
            nodeNameList.add(link.getNodeHeadName());
            nodeList.add(link.getNodeTail());
            nodeNameList.add(link.getNodeTailName());
            linkList.add(link.getId());
            linkNameList.add(link.getName());
            linkTypeList.add(link.getLayer());
        }
        // remove sourceNode and targetNode, passing nodes will be ordered without origin and destination
        nodeList.remove(origin.getNodeId());
        nodeNameList.remove(origin.getName());
        nodeList.remove(destination.getNodeId());
        nodeNameList.remove(destination.getName());
        // set route
        route.setNodeList(nodeList);
        route.setNodeNameList(nodeNameList);
        route.setLinkList(linkList);
        route.setLinkNameList(linkNameList);
        route.setLinkTypeList(linkTypeList);
        return route;
    }

    //返回正确的路由dto格式
    public static RouteType routeType(Route route) throws BaseException {
        Set<String> nodeList = route.getNodeList();
        List<String> nodeNameList = route.getNodeNameList();
        List<String> linkList = route.getLinkList();
        List<String> linkNameList = route.getLinkNameList();
        List<String> linkTypeList = route.getLinkTypeList();

        if (linkList == null || linkList.size() == 0) {
            return null;
        }
        List<RouteNodeType> nodeRes = new ArrayList<>();
        List<RouteLinkType> linkRes = new ArrayList<>();
        int nodeIndex = 0;
        for (String nodeId : nodeList) {
            String nodeName = nodeNameList.get(nodeIndex);
            nodeRes.add(new RouteNodeType(nodeId, nodeName));
            nodeIndex++;
        }
        for (int i = 0; i < linkList.size(); i++) {
            String linkId = linkList.get(i);
            String linkName = linkNameList.get(i);
            String linkType = linkTypeList.get(i);
            linkRes.add(new RouteLinkType(linkId, linkName, linkType));
        }
        return new RouteType(nodeRes, linkRes);
    }

    @Data
    public static final class RouteType implements Serializable {
        private List<RouteNodeType> nodeList = new ArrayList<>();
        private List<RouteLinkType> linklist = new ArrayList<>();

        public RouteType(List<RouteNodeType> nodeList, List<RouteLinkType> linklist) {
            this.nodeList = nodeList;
            this.linklist = linklist;
        }
    }

    @Data
    public static final class RouteNodeType implements Serializable {
        private String nodeId;
        private String name;

        public RouteNodeType(String nodeId, String name) {
            this.nodeId = nodeId;
            this.name = name;
        }
    }

    @Data
    public static final class RouteLinkType implements Serializable {
        private String linkId;
        private String name;
        private String type;

        public RouteLinkType(String linkId, String name, String type) {
            this.linkId = linkId;
            this.name = name;
            this.type = type;
        }
    }

    @Data
    public static final class DanDuanDto implements Serializable {
        private String trafficId;
        private String name;
        private String sourceName;
        private String targetName;
        private Integer year;
        private String layer;
        private String protect;
        private RouteType workRoute;//工作路由
        private RouteType protectRoute;//保护路由
        private RouteType workRoutePrev;//工作路由
        private RouteType protectRoutePrev;//保护路由
        private boolean recoveryFlag;//是否恢复成功
        private String error;//恢复失败原因

        public DanDuanDto() {
        }

        public DanDuanDto(String trafficId, String name, String sourceName, String targetName, Integer year, String layer, String protect, boolean recoveryFlag, String error,
                          RouteType workRoute, RouteType protectRoute, RouteType workRoutePrev, RouteType protectRoutePrev) {
            this.trafficId = trafficId;
            this.name = name;
            this.sourceName = sourceName;
            this.targetName = targetName;
            this.year = year;
            this.layer = layer;
            this.protect = protect;
            this.recoveryFlag = recoveryFlag;
            this.error = error;
            this.workRoute = workRoute;
            this.protectRoute = protectRoute;
            this.workRoutePrev = workRoutePrev;
            this.protectRoutePrev = protectRoutePrev;
        }
    }

    @Data
    public static final class DanDuanOneByOneDto implements Serializable {
        private String survivalId;
        private String name;
        private String type;
        private List<DanDuanDto> affectedList = new ArrayList<>();

        public DanDuanOneByOneDto() {
        }

        public DanDuanOneByOneDto(String survivalId, String name, String type, List<DanDuanDto> affectedList) {
            this.survivalId = survivalId;
            this.name = name;
            this.type = type;
            this.affectedList = affectedList;
        }
    }

}
